import os
import requests
from urllib3 import disable_warnings
from urllib3.exceptions import InsecureRequestWarning
from pickle import load, dump
from common.logger import logger
from common.types import SettingInfo, TransferInfo

__all__ = ['SessionWrapper', 'BaseAction']

config_file = '.config'

class Config(object):
	def __init__(self):
		self._last_username = ""
		self._all_sessions = {}

	def get_last_credential(self):
		return self._last_username, self.get_password_cached(self._last_username)

	def get_all_usernames(self):
		return self._all_sessions.keys()

	def get_password_cached(self, username):
		sess_core = self.get_session(username)
		if sess_core:
			return sess_core._password
		else:
			return ""

	def set_last_username(self, username):
		self._last_username = username

	def get_last_username(self):
		return self._last_username

	def set_session(self, username, sess_core):
		self.set_last_username(username)
		self._all_sessions[username] = sess_core

	def get_session(self, username):
		if username in self._all_sessions:
			return self._all_sessions[username]
		else:
			return None

	def serialize(self):
		with open(config_file, 'wb') as f:
			dump(self, f)

class SessionCore(object):
	def __init__(self):
		self._password = ""
		self._cookies = None
		self._sessionKey = ""
		self._sessionSecret = ""
		self._accessToken = ""
		self._settingInfo = SettingInfo()
		self._transferList = []

class SessionWrapper(object):
	def __init__(self):
		self._session = requests.Session()
		self._sessionKey = ""
		self._sessionSecret = ""
		self._accessToken = ""
		self._captchaToken = None
		self._userInfo = None

		self._config = None
		try:
			with open(config_file, 'rb') as f:
				self._config = load(f)
		except:
			pass
		if not self._config:
			self._config = Config()

		disable_warnings(InsecureRequestWarning)  # 全局禁用 SSL 警告

	def save_login_info(self, username, password):

		sess_core = SessionCore()
		sess_core._password = password
		sess_core._cookies = self.get_cookies()
		sess_core._sessionKey = self._sessionKey
		sess_core._sessionSecret = self._sessionSecret
		sess_core._accessToken = self._accessToken
		self._config.set_session(username, sess_core)

		self._config.serialize()

	def set_last_username(self, username):
		self._config.set_last_username(username)

	def get_last_credential(self):
		return self._config.get_last_credential()

	def get_all_usernames(self):
		return self._config.get_all_usernames()

	def get_password_cached(self, username):
		return self._config.get_password_cached(username)

	def set_session_from_config(self, username):
		sess_core = self._config.get_session(username)
		if not sess_core:
			return False

		self._sessionKey = sess_core._sessionKey
		self._sessionSecret = sess_core._sessionSecret
		self._accessToken = sess_core._accessToken
		for k, v in sess_core._cookies.items():
			self.set_cookie(k, v, domain=".cloud.189.cn")

		return True

	def set_session(self, key, secret, token):
		self._sessionKey = key
		self._sessionSecret = secret
		self._accessToken = token

	def get_session_key(self):
		return self._sessionKey

	def get_session_secret(self):
		return self._sessionSecret

	def get_session_access_token(self):
		return self._accessToken

	def get_cookies(self):
		return self._session.cookies.get_dict()

	def set_cookie(self, key, value, domain):
		cookie_obj = requests.cookies.create_cookie(domain=domain, name=key, value=value)
		self._session.cookies.set_cookie(cookie_obj)

	def clear_all_cookies(self):
		self._session.cookies.clear()

	def set_header(self, params):
		self._session.headers.update(params)

	def _get(self, url, **kwargs):
		return self._session.get(url, verify=False, **kwargs)

	def _post(self, url, data, **kwargs):
		return self._session.post(url, data, verify=False, **kwargs)

	def set_user_info(self, user_info):
		self._userInfo = user_info

	def get_user_info(self):
		return self._userInfo

	def set_captcha_token(self, captcha_token):
		self._captchaToken = captcha_token

	def get_captcha_token(self):
		return self._captchaToken

	def get_setting_info(self):
		username = self._config.get_last_username()
		sess_core = self._config.get_session(username)
		if not sess_core:
			return None

		setting_info = sess_core._settingInfo
		if not setting_info.downDir or len(setting_info.downDir) <= 0:
			setting_info.downDir = self.get_default_down_dir()

		return sess_core._settingInfo

	def save_setting_info(self, setting_info, apply_to_all):
		if len(setting_info.downDir) <= 0 or (not os.path.exists(setting_info.downDir)):
			setting_info.downDir = self.get_default_down_dir()

		if apply_to_all:
			for username in self._config._all_sessions:
				sess_core = self._config._all_sessions[username]
				sess_core._settingInfo = setting_info
		else:
			username = self._config.get_last_username()
			sess_core = self._config.get_session(username)
			if not sess_core:
				return False
			sess_core._settingInfo = setting_info

		self._config.serialize()
		return True

	def get_default_down_dir(self):
		file_dir = os.path.dirname(os.path.abspath(__file__))
		return os.path.dirname(file_dir) + os.sep + 'downloads'

	def get_transfer_list(self):
		username = self._config.get_last_username()
		sess_core = self._config.get_session(username)
		if not sess_core:
			return None
		return sess_core._transferList

	def save_config(self):
		# print('saving config')
		self._config.serialize()

class BaseAction(object):
	def __init__(self, sess_wp: SessionWrapper):
		self._sess_wp = sess_wp
		self._captcha_handler = None
		self._timeout = 15  # 每个请求的超时(不包含下载响应体的用时)
		self._host_url = 'https://cloud.189.cn'
		self._auth_url = 'https://open.e.189.cn/api/logbox/oauth2/'
		self._headers = {
			'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/76.0',
			'Referer': 'https://open.e.189.cn/',
		}

	def _get(self, url, **kwargs):
		try:
			kwargs.setdefault('timeout', self._timeout)
			kwargs.setdefault('headers', self._headers)
			return self._sess_wp._get(url, **kwargs)
		except requests.Timeout:
			logger.warning(
				"Encountered timeout error while requesting network!")
			raise TimeoutError
		except (requests.RequestException, Exception) as e:
			logger.error(f"Unexpected error: {e}")

	def _post(self, url, data, **kwargs):
		try:
			kwargs.setdefault('timeout', self._timeout)
			kwargs.setdefault('headers', self._headers)
			return self._sess_wp._post(url, data, **kwargs)
		except requests.Timeout:
			logger.warning(
				"Encountered timeout error while requesting network!")
			raise TimeoutError
		except (requests.RequestException, Exception) as e:
			logger.error(f"Unexpected error: {e}")

	def set_captcha_handler(self, captcha_handler):
		"""设置下载验证码处理函数
		:param captcha_handler (img_data) -> str 参数为图片二进制数据,需返回验证码字符
		"""
		self._captcha_handler = captcha_handler
